package com.ossean.match.matchprocess;

import java.io.IOException;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.ossean.match.dao.ProjectDao;
import com.ossean.match.dao.RelativeMemoToOpenSourceProjectDao;
import com.ossean.match.lucene.LuceneIndex;
import com.ossean.match.lucene.LuceneSearch;
import com.ossean.match.model.Project;
import com.ossean.match.model.RelativeMemo;
import com.ossean.match.model.RelativeMemoToOpenSourceProject;
import com.ossean.match.utils.ApplicationContextHelper;
import com.ossean.match.utils.Normalizer;

import javax.annotation.Resource;

@Component("match")
public class Match {
	private Logger logger = LoggerFactory.getLogger(getClass());
	private double memoTagsWeight = 1.0;
	private double prjTagsToMemoTagsWeight = 0.6;
	private double prjTagsToMemoTitleWeight = 0.5;
	private double titleWeight = 0.8;
	private double threshholdWeight = 1.3;

	@Resource
	private RelativeMemoToOpenSourceProjectDao matchResultDao;
	@Resource
	private ProjectDao projectDao;

	/**
	 * projects match to memos
	 * 
	 * @param projects
	 * @param prjHistory
	 * @param memoHistory
	 * @param tagOperator
	 * @param matchResultOperator
	 */
	public void prjToMemoMatch(List<Project> projects) {
		HashMap<Integer, Double> matchMap = new HashMap<Integer, Double>();
		try {
			Directory memoDire = FSDirectory.open(Paths
					.get(LuceneIndex.MEMOS_INDEX_PATH));
			if (!DirectoryReader.indexExists(memoDire)) { // if the index directory
														// doesn't exist
				return;
			}
			IndexReader memoIndexReader = DirectoryReader.open(memoDire);
			for(Project project : projects) {
				int prjId = 0;
				String prjName = "";
				String prjTags = "";
				String synonyms = "";
				prjId = project.getId();
				if (project.getName() == null || project.getName() == "")
					continue;
				if(project.getTags() != null)
					prjTags = project.getTags().toLowerCase();
				prjName = project.getName().toLowerCase();
				if (prjName.length() >= 2 && !Normalizer.isAllNumber(prjName)) {
					// 项目名匹配帖子标题
					matchMap = LuceneSearch.prjToMemoMatchByLucene(prjName, 
							   LuceneIndex.titleFieldName, titleWeight, matchMap, memoIndexReader);
//System.out.println("项目名匹配帖子标题"+matchMap.size());
					// 项目名匹配帖子标签
					matchMap = LuceneSearch.searchMemoTags( 
							prjName, LuceneIndex.memoTagsFieldName, LuceneIndex.memoIdFieldName, memoTagsWeight,
							matchMap, memoIndexReader);
//System.out.println("项目名匹配帖子标签"+matchMap.size());
				}
				if (project.getSynonyms() != null) {
					synonyms = project.getSynonyms().toLowerCase();
					List<String> synonymsList = Normalizer.tagsSegmentation(synonyms);
					if (synonymsList.size() > 0) {
						//项目别名匹配帖子标题 TODO
						for (String synonym : synonymsList) {
							matchMap = LuceneSearch.prjToMemoMatchByLucene(synonym, 
									   LuceneIndex.titleFieldName, titleWeight, matchMap, memoIndexReader);
						}
//System.out.println("项目别名匹配帖子标题 "+matchMap.size());
						//项目别名匹配帖子标签 TODO
						for (String synonym : synonymsList) {
							matchMap = LuceneSearch.searchMemoTags( 
									synonym, LuceneIndex.memoTagsFieldName, LuceneIndex.memoIdFieldName, memoTagsWeight,
									matchMap, memoIndexReader);
						}
//System.out.println("项目别名匹配帖子标签 "+matchMap.size());
					}
				}
				if (prjTags != null && prjTags.length() > 0 && matchMap.size() > 0) {
					List<String> prjTagsList = Normalizer.tagsSegmentation(prjTags);
					// 用项目标签搜索帖子标题
					for (String prjTag : prjTagsList) {
						matchMap = LuceneSearch.searchByPrjTagInMemoTitle(
								prjTag, LuceneIndex.titleFieldName, LuceneIndex.memoIdFieldName, prjTagsToMemoTitleWeight,
								matchMap, memoIndexReader);
					}
//System.out.println("用项目标签搜索帖子标题 "+matchMap.size());
					// 用项目标签搜索帖子标签
					for (String prjTag : prjTagsList) {
						matchMap = LuceneSearch.searchByPrjTag(
								prjTag, LuceneIndex.memoTagsFieldName, LuceneIndex.memoIdFieldName, prjTagsToMemoTagsWeight,
								matchMap, memoIndexReader);
					}
//System.out.println("用项目标签搜索帖子标签 "+matchMap.size());
				}
				if (matchMap.size() > 0)
					insertPrjToMemoMatchResult(prjId, matchMap);
				matchMap.clear();
				projectDao.updateProcessedPrj(prjId);
				logger.info("current prjId: " + prjId);
			}
			memoIndexReader.close();
			memoDire.close();
		} catch (IOException e) {
			logger.error("prjToMemoMatch io error in Match: " + e);
		}
	}
	
	/**
	 *项目匹配帖子结果入库
	 * @param prjId
	 * @param matchMap
	 */
	@Transactional(propagation=Propagation.REQUIRES_NEW)
	public void insertPrjToMemoMatchResult(int prjId, HashMap<Integer, Double> matchMap) {
		//long start = System.currentTimeMillis();
		List<RelativeMemoToOpenSourceProject> list = new ArrayList<RelativeMemoToOpenSourceProject>();
		for (Map.Entry<Integer, Double> entry : matchMap.entrySet()) {
			try {
				int memoId = entry.getKey();
				double weight = entry.getValue();
				if (weight > threshholdWeight) {
					RelativeMemoToOpenSourceProject matchResult = new RelativeMemoToOpenSourceProject();
					matchResult.setOsp_id(prjId);
					matchResult.setRelative_memo_id(memoId);
					matchResult.setMatch_weight(weight);
					list.add(matchResult);
					
					//matchResultDao.insertMatchResult(getTargetTable(prjId), matchResult);
				}
				if(list.size()==800 || list.size()==matchMap.size()){
					batchInsertJDBC(list,getTargetTable(prjId));
					//matchResultDao.insertMatchResultBatch(getTargetTable(prjId), list);
					list.clear();
				}
					
			} catch (Exception e) {
				logger.error("insertPrjToMemoMatchResult error: " + e);
			}
		}
		if(list.size()!=0)
			batchInsertJDBC(list,getTargetTable(prjId));
		//System.out.println(prjId+" current insert time cost:"+(System.currentTimeMillis()-start)/1000+" seconds");
	}
	
	@Transactional()  
	public void batchInsertJDBC(List<RelativeMemoToOpenSourceProject> list,String tableName) throws DataAccessException {
		
		JdbcTemplate jdbcTemplate=(JdbcTemplate)ApplicationContextHelper.getBean("jdbcTemplate");
	    StringBuilder sqlbuf = new StringBuilder()  
	        .append("insert ignore  into "+tableName+" (osp_id,relative_memo_id,match_weight,match_time) values  ");  
	    for (RelativeMemoToOpenSourceProject prj :list) {
	    	SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
	        sqlbuf.append("("+prj.getOsp_id()+","+prj.getRelative_memo_id()+","
	        		+prj.getMatch_weight()+",'"+df.format(new Date())+"')");
	        sqlbuf.append(",");
	    }  
	    String sql = sqlbuf.toString();  
	    sql = sql.substring(0, sql.length()-1);  
	    jdbcTemplate.update(sql);  
	}
	
	/**
	 * get the match result table's name
	 * @param osp_id
	 * @return
	 */
	public static String getTargetTable(int ospId){
		String targetTableName = "";
		if(ospId >= 770000 && ospId <= 800000){
			targetTableName = "relative_memo_to_open_source_projects_70";
		}
		else if(ospId > 800000 && ospId<78000000) {
			int tmp = 71 + ospId%20;
			targetTableName = "relative_memo_to_open_source_projects_" + tmp;
		}
		else{
				int a = 1 + ospId/11000;
				targetTableName = "relative_memo_to_open_source_projects_" + a;
		}

		return targetTableName;
	}

	/**
	 * memos match to projects
	 * 
	 * @param memos
	 * @param prjHistory
	 * @param memoHistory
	 * @param tagOperator
	 * @param matchResultOperator
	 */
	public void memoToPrjMatch(List<RelativeMemo> memos) {
		HashMap<Integer, Double> matchMap = new HashMap<Integer, Double>();
		try {
			Directory prjDire = FSDirectory.open(Paths
					.get(LuceneIndex.PRJS_INDEX_PATH));
			if (!DirectoryReader.indexExists(prjDire)) { // if the index directory
														// doesn't exist
				return;
			}
			IndexReader prjIndexReader = DirectoryReader.open(prjDire);
			for(RelativeMemo memo : memos) {
				int memoId = 0;
				String memoTitle = "";
				String memoTags = "";
				memoId = memo.getId();
				if (memo.getTitle() == null || memo.getTitle().length() == 0) {
					continue;
				}
				if (memo.getTags() != null && memo.getTags().length() > 0) {
					memoTags = memo.getTags().toLowerCase();
				}
				memoTitle = memo.getTitle().toLowerCase();
//				if (memoTitle.length() == 0) {
//					continue;
//				}
				if (Normalizer.isAllNumber(memoTitle)) {
					continue;
				}
				List<String> memoTitleList = Normalizer.getList(memoTitle);
				if (memoTitleList.size() > 0) {
					// 帖子标题匹配项目名
					matchMap = LuceneSearch.memoToPrjMatchByLucene(memoTitle,
							memoTitleList, LuceneIndex.prjNameFieldName,
							titleWeight, matchMap, prjIndexReader);
					//帖子标题搜索项目别名
					matchMap = LuceneSearch.memoToPrjMatchByLucene(memoTitle,
							memoTitleList, LuceneIndex.prjSynonymsFieldName,
							titleWeight, matchMap, prjIndexReader);
				}
				List<String> memoTagsList = Normalizer.tagsSegmentation(memo.getTags().toLowerCase());
				// 用帖子标签搜索项目名
				if (memoTags.length() > 0 && memoTagsList.size() > 0) {
					//用帖子标签搜索项目名
					for (String memoTag : memoTagsList) {
						matchMap = LuceneSearch.searchMemoTags(memoTag, 
								   LuceneIndex.prjNameFieldName, LuceneIndex.prjIdFieldName, memoTagsWeight, matchMap, prjIndexReader);
					}
					//用帖子标签搜索项目别名
					for (String tag : memoTagsList) {
						matchMap = LuceneSearch.searchMemoTags(tag, 
								   LuceneIndex.prjSynonymsFieldName, LuceneIndex.prjIdFieldName, memoTagsWeight, matchMap, prjIndexReader);
					}
				}
				if (matchMap.size() > 0) {
					// 帖子标题匹配项目标签
					if (memoTitleList != null && memoTitleList.size() > 0) {
						for (String memoTitleTerm : memoTitleList) {
							matchMap = LuceneSearch.searchByPrjTag(
									memoTitleTerm, LuceneIndex.prjTagsFieldName, LuceneIndex.prjIdFieldName, prjTagsToMemoTitleWeight,
									matchMap, prjIndexReader);
						}
					}
					// 用帖子标签搜索项目标签
					if (memo.getTags() != null && memo.getTags().length() > 0) {
						for (String memoTag : memoTagsList) {
							matchMap = LuceneSearch.searchByPrjTag(
									memoTag, LuceneIndex.prjTagsFieldName, LuceneIndex.prjIdFieldName, prjTagsToMemoTagsWeight,
									matchMap, prjIndexReader);
						}
					}
					if (matchMap.size() > 0)
						insertMemoToPrjMatchResult(memoId, matchMap);
				}

				matchMap.clear();
				logger.info("current MemoId: " + memoId);
			}
			prjIndexReader.close();
			prjDire.close();
		} catch (Exception e) {
			logger.error("memoToPrjMatch error in Match: " + e);
		}
	}
	
	/**
	 * 帖子匹配项目结果入库
	 * @param memoId
	 * @param matchMap
	 */
	@Transactional(propagation=Propagation.REQUIRES_NEW)
	public void insertMemoToPrjMatchResult(int memoId, HashMap<Integer, Double> matchMap) {
		for (Map.Entry<Integer, Double> entry : matchMap.entrySet()) {
			try {
				int prjId = entry.getKey();
				if(projectDao.getPrjById(prjId).getFiltration() > 0){
					double weight = entry.getValue();
					if (weight > threshholdWeight) {
						RelativeMemoToOpenSourceProject matchResult = new RelativeMemoToOpenSourceProject();
						matchResult.setOsp_id(prjId);
						matchResult.setRelative_memo_id(memoId);
						matchResult.setMatch_weight(weight);
						matchResultDao.insertMatchResult(getTargetTable(prjId), matchResult);
					}
				}
			} catch (Exception e) {
				logger.error("insertMemoToPrjMatchResult error: " + e);
			}
		}
	}

}
